#ifndef SSHSFTPCONNECTION_H
#define SSHSFTPCONNECTION_H

#include <QMetaType>
#include <QObject>
#include <libssh/sftp.h>

#include "QLibSsh_global.h"
#include "sshsession.h"

class QLIBSSH_EXPORT SshSftpConnection final : public QObject
{
    Q_OBJECT

public:
    class SftpSession final : public SharePtr<sftp_session> {
    public:
        explicit SftpSession(const sftp_session& session) : SharePtr(session) {}
        ~SftpSession() override {
            if (mPtr == nullptr) {
                return;
            }
            mRefCount->fetch_sub(1, std::memory_order_relaxed);
            if (mRefCount->load(std::memory_order_relaxed) == 0) {
                qDebug() << "SftpSession::~SftpSession";
                sftp_free(mPtr);
            }
            mPtr = nullptr;
            mRefCount = nullptr;
        }
    };

    class SftpFile final : public SharePtr<sftp_file> {
    public:
        explicit SftpFile(const sftp_file& file) : SharePtr(file) {}
        ~SftpFile() override {
            if (mPtr == nullptr) {
                return;
            }
            mRefCount->fetch_sub(1, std::memory_order_relaxed);
            if (mRefCount->load(std::memory_order_relaxed) == 0) {
                sftp_close(mPtr);
                delete mRefCount;
                qDebug() << "SftpFile::~SftpFile()";
            }

            mPtr = nullptr;
            mRefCount = nullptr;
        }
    };

    class SftpDir final  : public SharePtr<sftp_dir> {
        public:
            explicit SftpDir(const sftp_dir& dir) : SharePtr(dir) {}
            ~SftpDir() override {
                if (mPtr == nullptr) {
                    return;
                }
                mRefCount->fetch_sub(1, std::memory_order_relaxed);
                if (mRefCount->load(std::memory_order_relaxed) == 0) {
                    sftp_closedir(mPtr);
                    delete mRefCount;
                    qDebug() << "SftpDir::~SftpDir()";
                }

                mPtr = nullptr;
                mRefCount = nullptr;
            }
    };

    explicit SshSftpConnection(SshLoginKeys  loginKeys, QObject* parent = nullptr);

    void connectSftp();
    bool CreateDir(const char* path, mode_t mode) const;
    bool RemoveDir(const char* path) const;
    SftpDir OpenDir(const char* path) const;
    SftpFile OpenFile(const char* filePath, int accessType, mode_t mode=0) const;
    bool RemoveFile(const char* target) const;
    [[nodiscard]] static QByteArray ReadFile(const SftpFile& file) ;

    static bool WriteFile(const SftpFile& file, const QByteArray& buffer);
    bool SeekFile() const;
    bool SeekFile64() const;
    bool SoftLink(const char* target, const char* linkPath) const;
    bool HardLink(const char* target, const char* linkPath) const;
    bool Unlink(const char* target) const;
    const char* ReadLink(const char* target) const;
    bool Rename(const char* original, const char* newest) const;
    [[nodiscard]] QStringList DisplayDirContents(const SftpDir& dir) const;

    // delete掉拷贝构造，重载移动构造赋值
    SshSftpConnection(const SshSftpConnection &) = delete;
    SshSftpConnection& operator=(const SshSftpConnection &) = delete;
    SshSftpConnection(SshSftpConnection&& other) noexcept;
    SshSftpConnection& operator=(SshSftpConnection&& other) noexcept;

private:
    bool InitSftp(const SshSession& sshSession);

    SshLoginKeys mSshLoginKeys;
    SshSession sshSession {};
    SftpSession sftp {nullptr};
};

#endif // SSHSFTPCONNECTION_H
